/**
 * 需求：实现一个图片懒加载指令，只加载浏览器可见区域的图片。
    思路：
    图片懒加载的原理主要是判断当前图片是否到了可视区域这一核心逻辑实现的
    拿到所有的图片 Dom ，遍历每个图片判断当前图片是否到了可视区范围内
    如果到了就设置图片的 src 属性，否则显示默认图片
    图片懒加载有两种方式可以实现，一是绑定 srcoll 事件进行监听，二是使用 IntersectionObserver 判断图片是否到了可视区域，
    但是有浏览器兼容性问题。
    下面封装一个懒加载指令兼容两种方法，判断浏览器是否支持 IntersectionObserver API，
    如果支持就使用 IntersectionObserver 实现懒加载，否则则使用 srcoll 事件监听 + 节流的方法实现。

    使用时:<img v-LazyLoad="xxx.jpg" /> 将组件内 标签的 src 换成 v-LazyLoad
 */

export default {
    install(Vue, options) {
        const defaultSrc = options.default;
        Vue.directive("lazy", {
            bind(el, binding) {
                LazyLoad.init(el, binding.value, defaultSrc);
            },
            inserted(el) {
                if (IntersectionObserver) {
                    LazyLoad.observe(el);
                } else {
                    LazyLoad.listenerScroll(el);
                }
            },
        });
    },
    // 初始化
    init(el, val, def) {
        el.setAttribute("data-src", val);
        el.setAttribute("src", def);
    },
    // 利用IntersectionObserver监听el
    observe(el) {
        var io = new IntersectionObserver((entries) => {
            const realSrc = el.dataset.src;
            if (entries[0].isIntersecting) {
                if (realSrc) {
                    el.src = realSrc;
                    el.removeAttribute("data-src");
                }
            }
        });
        io.observe(el);
    },
    // 监听scroll事件
    listenerScroll(el) {
        const handler = LazyLoad.throttle(LazyLoad.load, 300);
        LazyLoad.load(el);
        window.addEventListener("scroll", () => {
            handler(el);
        });
    },
    // 加载真实图片
    load(el) {
        const windowHeight = document.documentElement.clientHeight;
        const elTop = el.getBoundingClientRect().top;
        const elBtm = el.getBoundingClientRect().bottom;
        const realSrc = el.dataset.src;
        if (elTop - windowHeight < 0 && elBtm > 0) {
            if (realSrc) {
                el.src = realSrc;
                el.removeAttribute("data-src");
            }
        }
    },
    // 节流
    throttle(fn, delay) {
        let timer;
        let prevTime;
        return function (...args) {
            const currTime = Date.now();
            const context = this;
            if (!prevTime) prevTime = currTime;
            clearTimeout(timer);

            if (currTime - prevTime > delay) {
                prevTime = currTime;
                fn.apply(context, args);
                clearTimeout(timer);
                return;
            }

            timer = setTimeout(function () {
                prevTime = Date.now();
                timer = null;
                fn.apply(context, args);
            }, delay);
        };
    },
};
